package com.game.commons.database;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.log4j.Logger;

import com.game.commons.configuration.ConfigurableProcessor;
import com.game.commons.utils.PropertiesUtils;


/**
 * <b>数据库工厂</b><br>
 * <br>
 * 利用database.properties中的配置，创建一个连接，并自动回收时关闭.<br>
 * <br>
 * {@link com.game.commons.database.DB}SQL操作工具类.<br>
 * <br>
 * <p/>
 * 
 * @author 杜祥
 * @create 2013-6-29
 */
public class DatabaseFactory
{

	private static final Logger			log	= Logger.getLogger(DatabaseFactory.class);

	/**
	 * 负责生成所有连接
	 */
	private static DataSource			dataSource;

	/**
	 * 持有所有连接的连接池
	 */
	private static GenericObjectPool	connectionPool;

	/**
	 * 数据库的名称
	 * 
	 */
	private static String				databaseName;

	/**
	 * 返回数据库的主要版本
	 */
	private static int					databaseMajorVersion;

	/**
	 * 返回数据的次要版本
	 */
	private static int					databaseMinorVersion;

	/**
	 * 初始化数据库
	 */
	public synchronized static void init()
	{
		init("");
	}
	
	/**
	 * 初始化数据库，并设置database.properties物理地址
	 * @param configFilePath			database.properties文件的路径
	 */
	public synchronized static void init(String configFilePath)
	{
		if(dataSource != null)
		{
			return;
		}
		
		if(!configFilePath.equals(""))
		{
			try
			{
				Properties dbProps = PropertiesUtils.load(configFilePath);
				ConfigurableProcessor.process(DatabaseConfig.class, dbProps);
			}
			catch(IOException ex)
			{
				log.fatal("无法加载数据库配置", ex);
			}
		}

		try
		{
			DatabaseConfig.DATABASE_DRIVER.newInstance();
		}
		catch(Exception e)
		{
			log.fatal("数据库驱动出错", e);
			throw new Error("DB驱动不存在!");
		}

		connectionPool = new GenericObjectPool();

		if(DatabaseConfig.DATABASE_CONNECTIONS_MIN > DatabaseConfig.DATABASE_CONNECTIONS_MAX)
		{
			log.error("数据库配置出错，最小连接数大于最大连接数");
			DatabaseConfig.DATABASE_CONNECTIONS_MAX = DatabaseConfig.DATABASE_CONNECTIONS_MIN;
		}

		connectionPool.setMaxIdle(DatabaseConfig.DATABASE_CONNECTIONS_MIN);
		connectionPool.setMaxActive(DatabaseConfig.DATABASE_CONNECTIONS_MAX);

		try
		{
			dataSource = setupDataSource();
			Connection c = getConnection();
			DatabaseMetaData dmd = c.getMetaData();
			databaseName = dmd.getDatabaseProductName();
			databaseMajorVersion = dmd.getDatabaseMajorVersion();
			databaseMinorVersion = dmd.getDatabaseMinorVersion();
			c.close();
		}
		catch(Exception e)
		{
			log.fatal("数据库连接出错: " + DatabaseConfig.DATABASE_URL, e);
			throw new Error("没有初始化数据库连接池!");
		}

		log.info("数据库连接成功，连接池初始化完成！");
	}

	/**
	 * 设置连接工厂
	 * 
	 * @return 数据源
	 * @throws Exception
	 *             初始化失败
	 */
	private static DataSource setupDataSource() throws Exception
	{
		ConnectionFactory conFactory = new DriverManagerConnectionFactory(DatabaseConfig.DATABASE_URL,
			DatabaseConfig.DATABASE_USER, DatabaseConfig.DATABASE_PASSWORD);

		new PoolableConnectionFactoryAE(conFactory, connectionPool, null, 1, false, true);

		return new PoolingDataSource(connectionPool);
	}

	/**
	 * 返回一个连接
	 * 
	 * @return 连接
	 * @throws java.sql.SQLException
	 *             无法获得连接时抛出此异常。
	 */
	public static Connection getConnection() throws SQLException
	{
		return dataSource.getConnection();
	}

	/**
	 * 返回连接池活跃的连接数
	 * 
	 * @return 活跃的连接数
	 */
	public int getActiveConnections()
	{
		return connectionPool.getNumActive();
	}

	/**
	 * 返回空闲的连接数
	 * 
	 * @return 空闲的连接数
	 */
	public int getIdleConnections()
	{
		return connectionPool.getNumIdle();
	}

	/**
	 * 关闭连接池
	 */
	public static synchronized void shutdown()
	{
		try
		{
			connectionPool.close();
		}
		catch(Exception e)
		{
			log.warn("无法关闭数据库工厂", e);
		}

		dataSource = null;
	}

	/**
	 * 关闭连接方法
	 * @param con			连接
	 */
	public static void close(Connection con)
	{
		if (con == null)
			return;
		
		try
		{
			con.close();
		}
		catch (SQLException e)
		{
			log.warn("DatabaseFactory: 关闭数据库连接刺柏!", e);
		}
	}

	/**
	 * 返回数据库名称
	 * 
	 * @return 数据库名称
	 */
	public static String getDatabaseName()
	{
		return databaseName;
	}

	/**
	 * 返回数据库的主板本号。
	 * 
	 * @return 主板本
	 */
	public static int getDatabaseMajorVersion()
	{
		return databaseMajorVersion;
	}

	/**
	 * 返回数据库的次版本号。
	 * 
	 * @return 次版本号
	 */
	public static int getDatabaseMinorVersion()
	{
		return databaseMinorVersion;
	}

	/**
	 * 默认构造函数
	 */
	private DatabaseFactory()
	{
		//
	}
}